SpringBoot 整合 MyBatis
配置连接池
注意:如果使用的是 MyBatis-Plus 或者 mybatis-spring-boot-starter
则默认会导入 spring-boot-starter-jdbc
不过一般使用的都是这两个,所以可以不用配置连接池了~
先引入数据连接池依赖
添加 JDBC 启动器,引入这个启动器就自动会使用 Spring 的 hikari 数据库连接池(默认的)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
或者使用 druid 数据连接池:参考文档 Druid Spring Boot Starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
添加数据库驱动
因为 SpringBoot 并不知道使用的数据库是什么,所以需要添加 MySQL 的驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
配置连接池
前面那种自定义写配置文件读取的方式现在可以改了,导入这个启动器之后就可以直接使用定义好的 SpringProperties
配置项
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_test?useUnicode=true&characterEncoding=utf8&useSSL=true&useServerPrepStmts=true
username: root
password: root
配置环境
官方文档 使用 MyBatis 的启动器(非 Spring 官方,只是 MyBatis 自己出的)
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
配置文件上加上 mybatis 的配置
mybatis:
type-aliases-package: com.alsritter.pojo # 实体类别名包路径,配了这个就无需在写全类名了
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 设置日志为后台输出
在启动器加上一个 @MapperScan
注解会把这个包下所有的接口都编译成响应的实现类(如果不想这样扫描包,可以继续使用 @Mapper
注解)
加上这个注解之后就无需在每个 Mapper 上加 @Mapper
注解了
@SpringBootApplication
@MapperScan("com.alsritter.mapper")
public class StudyApplication {
public static void main(String[] args) {
SpringApplication.run(StudyApplication.class, args);
}
}
甚至可以扫描多个包
@MapperScan({"com.alsritter.mapper","com.alsritter.temp"})
使用 XML 配置 Mapper
如果是普通开发其实可以只使用注解,但是一些动态 SQL 需要在配置文件上配置,否则很麻烦
补个 SQL 命令:查看表结构 DESC table_name
所以还是需要用到 XML 来配置(两个可以混起来使用)
首先配置 yml
mybatis:
type-aliases-package: com.alsritter.pojo # 实体类别名包路径,配了这个就无需在写全类名了
mapper-locations: classpath:mapper/*.xml
在 resources 目录下创建 mapper 目录,里面写 mapper 文件
编写接口(还是需要使用接口,因为需要自动注入,只用 xml 文件的方式太极端了)
public interface UserMapper {
// 可以和 注解 混搭使用
@Select("select * from tb_user")
List<User> getUserList();
@Transactional
int insertUser(User user);
}
编写 mapper 文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--这里写接口的包名-->
<mapper namespace="com.alsritter.mapper.UserMapper">
<insert id="insertUser" parameterType="User">
insert into springboot_test.tb_user
<trim prefix="(" suffix=")" suffixOverrides=",">
user_name,
password,
<if test="age != null">
age,
</if>
<if test="sex != null">
sex,
</if>
<if test="birthday != null">
birthday,
</if>
<if test="note != null">
note,
</if>
<if test="created != null">
created,
</if>
<if test="updated != null">
updated,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
#{userName},
#{password},
<if test="age != null">
#{age},
</if>
<if test="sex != null">
#{sex},
</if>
<if test="birthday != null">
#{birthday},
</if>
<if test="note != null">
#{note},
</if>
<if test="created != null">
#{created},
</if>
<if test="updated != null">
#{updated},
</if>
</trim>
</insert>
</mapper>
Service 层
只需加上 @Transactional
注解就能自动回滚了
@Service
public class UserService {
private UserMapper userMapper;
@Resource
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
// 新增保存用户(因为新增用户可能会失败,所以需要使用事务进行回滚)
@Transactional
public void insertUser(User user) {
userMapper.insertUser(user);
}
}
测试类
Mapper 层
public interface UserMapper {
@Select("select * from tb_user")
List<User> getUserList();
}
Service 层
参考资料 springboot整合mybatis mapper注入时报错could not autowire,几种解决方案
注意:这里有个 IDEA 的 BUG,就是会显示找不到 UserMapper 的错,但是实际可以运行
可以把 @Autowired
改成 @Resource
,绕过 IDEA 的检测机制就不会报错了
@Service
public class UserService {
private UserMapper userMapper;
@Autowired
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
// 新增保存用户(因为新增用户可能会失败,所以需要使用事务进行回滚)
@Transactional
public void saveUser(User user) {
userMapper.getUserList().forEach(System.out::println);
}
}
Controller 层
@Slf4j
@RequestMapping("/hello")
@RestController
public class HelloController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@GetMapping("/temp1")
public String hello() {
userService.saveUser(new User());
return "hot update";
}
}
单元测试
@SpringBootTest
class StudyApplicationTests {
@Autowired
private HelloController helloController;
@Test
void contextLoads() {
helloController.hello();
}
}
事务配置
只需加上 @Transactional
注解就能自动回滚了
注意:事务捕获异常 参看 Spring02 笔记
// 新增保存用户(因为新增用户可能会失败,所以需要使用事务进行回滚)
@Transactional
public int insertUser(User user) {
int i = 0 ;
try {
i = userMapper.insertUser(user);
} catch (Exception e) {
log.warn(e.getMessage());
// 注意,需要手动强制回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return i;
}
注解结果集映射
注解 @Results
和 @Result
来结果集映射
<mapper namespace="data.UserMapper">
<resultMap type="data.User" id="userResultMap">
<!-- 用id属性来映射主键字段 -->
<id property="id" column="user_id"/>
<!-- 用result属性来映射非主键字段 -->
<result property="userName" column="user_name"/>
</resultMap>
</mapper>
使用注解的形式
public interface AdminMapper {
@Results(id = "admin", value = {
@Result(column = "work_id", property = "id"),
@Result(column = "join_date", property = "joinDate")
})
@Select("select * from ADMIN_TB where work_id=#{workId} and password=#{password}")
Admin getAdmin(String workId, String password);
@ResultMap("admin")
@Select("select * from ADMIN_TB where work_id=#{workId}")
Admin getAdminSelf(String workId);
// 用来把管理员 id 更新到 redis
@Select("select work_id from ADMIN_TB")
List<String> getWorkerIdList();
int updateUser(Admin admin);
}